Purpose: The purpose of this project is to analyze a number of trends in the Apple App Store. I chose to do this project using this data because I’m interested in mobile app development and currently have an application on the App Store. Specifically, my application is for music and social media, so I will be heavily analyzing these genres specifically.
# clean up workspace environment
rm(list = ls())
#Packages
library(mosaic)
Loading required package: dplyr
Registered S3 method overwritten by 'dplyr':
method from
print.rowwise_df
Attaching package: 㤼㸱dplyr㤼㸲
The following objects are masked from 㤼㸱package:stats㤼㸲:
filter, lag
The following objects are masked from 㤼㸱package:base㤼㸲:
intersect, setdiff, setequal, union
Loading required package: lattice
Loading required package: ggformula
Loading required package: ggplot2
Loading required package: ggstance
Attaching package: 㤼㸱ggstance㤼㸲
The following objects are masked from 㤼㸱package:ggplot2㤼㸲:
geom_errorbarh, GeomErrorbarh
New to ggformula? Try the tutorials:
learnr::run_tutorial("introduction", package = "ggformula")
learnr::run_tutorial("refining", package = "ggformula")
Loading required package: mosaicData
Loading required package: Matrix
Registered S3 methods overwritten by 'htmltools':
method from
print.html tools:rstudio
print.shiny.tag tools:rstudio
print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
Registered S3 method overwritten by 'mosaic':
method from
fortify.SpatialPolygonsDataFrame ggplot2
The 'mosaic' package masks several functions from core packages in order to add
additional features. The original behavior of these functions should not be affected by this.
Note: If you use the Matrix package, be sure to load it BEFORE loading mosaic.
Attaching package: 㤼㸱mosaic㤼㸲
The following object is masked from 㤼㸱package:Matrix㤼㸲:
mean
The following object is masked from 㤼㸱package:ggplot2㤼㸲:
stat
The following objects are masked from 㤼㸱package:dplyr㤼㸲:
count, do, tally
The following objects are masked from 㤼㸱package:stats㤼㸲:
binom.test, cor, cor.test, cov, fivenum, IQR, median, prop.test, quantile,
sd, t.test, var
The following objects are masked from 㤼㸱package:base㤼㸲:
max, mean, min, prod, range, sample, sum
library(tidyverse)
[37m-- [1mAttaching packages[22m --------------------------------------- tidyverse 1.2.1 --[39m
[37m[32mv[37m [34mtibble [37m 2.1.3 [32mv[37m [34mpurrr [37m 0.3.2
[32mv[37m [34mtidyr [37m 1.0.0 [32mv[37m [34mstringr[37m 1.4.0
[32mv[37m [34mreadr [37m 1.3.1 [32mv[37m [34mforcats[37m 0.4.0[39m
[37m-- [1mConflicts[22m ------------------------------------------ tidyverse_conflicts() --
[31mx[37m [34mmosaic[37m::[32mcount()[37m masks [34mdplyr[37m::count()
[31mx[37m [34mpurrr[37m::[32mcross()[37m masks [34mmosaic[37m::cross()
[31mx[37m [34mmosaic[37m::[32mdo()[37m masks [34mdplyr[37m::do()
[31mx[37m [34mtidyr[37m::[32mexpand()[37m masks [34mMatrix[37m::expand()
[31mx[37m [34mdplyr[37m::[32mfilter()[37m masks [34mstats[37m::filter()
[31mx[37m [34mggstance[37m::[32mgeom_errorbarh()[37m masks [34mggplot2[37m::geom_errorbarh()
[31mx[37m [34mdplyr[37m::[32mlag()[37m masks [34mstats[37m::lag()
[31mx[37m [34mtidyr[37m::[32mpack()[37m masks [34mMatrix[37m::pack()
[31mx[37m [34mmosaic[37m::[32mstat()[37m masks [34mggplot2[37m::stat()
[31mx[37m [34mmosaic[37m::[32mtally()[37m masks [34mdplyr[37m::tally()
[31mx[37m [34mtidyr[37m::[32munpack()[37m masks [34mMatrix[37m::unpack()[39m
library(DataComputing)
library(party)
Loading required package: grid
Loading required package: mvtnorm
Loading required package: modeltools
Loading required package: stats4
Loading required package: strucchange
Loading required package: zoo
Attaching package: 㤼㸱zoo㤼㸲
The following objects are masked from 㤼㸱package:base㤼㸲:
as.Date, as.Date.numeric
Loading required package: sandwich
Attaching package: 㤼㸱strucchange㤼㸲
The following object is masked from 㤼㸱package:stringr㤼㸲:
boundary
The chunk below loads all data from the two datasets regarding the Apple App Store
#This dataset contains a number of analytics about over 7000 applications on the App Store.
#Information includes rating, price, genre, etc.
dataset_1 <- 'C:/Users/angel/Dropbox/Penn State/STAT 184/Project/App_Store_Analysis/AppleStore.csv'
App_Store_Data <- read.csv(file = dataset_1, header=TRUE, sep=",")
#This dataset contains a number of analytics about over 7000 applications on the App Store.
#Information includes rating, price, genre, etc.
dataset_2 <- 'C:/Users/angel/Dropbox/Penn State/STAT 184/Project/App_Store_Analysis/appleStore_description.csv'
App_Store_Description_Data <- read.csv(file = dataset_2, header=TRUE, sep=",")
Sample of the App Store Dataset
App_Store_Data %>%
sample_n(size = 10)
Sample of the Description Dataset
App_Store_Description_Data %>%
sample_n(size = 10)
General Analysis
The first thing that I wanted to do with this dataset is gather some general statistics about the apps within the App Store. Below shows several mean values calculated based on this data.
#This code displays the mean size of each app, app rating, and number of languages supported within an app.
App_Store_Data %>%
summarise(num_apps = n(),
mean_app_size = mean(size_bytes),
mean_app_rating = mean(user_rating),
mean_supported_languages = mean(lang.num))
App Store Breakdown
The following is a general breakdown of the categories of apps in the App Store. Below is a chart containing the specific number of apps in each category, in addition to a plot showing these numbers. This plot shows a more visually appealing way of looking at just how diverse the App Store really is. Based on this data, it’s very clear that games take up a very large population in the App Store.
App_Categories <- App_Store_Data %>%
group_by(prime_genre) %>%
summarise(num_on_store = n())
App_Categories
ggplot(data=App_Categories,aes(x=prime_genre,y=num_on_store ,fill=prime_genre))+geom_bar(stat='identity',position='stack', width=.9)+theme(axis.text.x=element_text(angle = 90, vjust = 0.5))+ xlab('App Category') + ylab('Number on Store')

Specific classification for Music and Social Media
Because my application is specifically related to music and social networking, I decided to focus on these categories.
#music data
Music_App_Data <-
App_Store_Data %>%
filter(prime_genre == 'Music')
#social network data
Social_Network_App_Data <-
App_Store_Data %>%
filter(prime_genre == 'Social Networking')
#join the music data with it's description
Music_With_Desc <- Music_App_Data %>%
left_join(App_Store_Description_Data, 'id' = 'id')
Joining, by = c("id", "track_name", "size_bytes")
#join social network data withn its description
Social_With_Desc <- Social_Network_App_Data %>%
left_join(App_Store_Description_Data, 'id' = 'id')
Joining, by = c("id", "track_name", "size_bytes")
#get most rated and highest rated music app names
Highest_Rated_Music <-
Music_With_Desc %>%
filter(user_rating >= 3.5) %>%
arrange(desc(rating_count_tot)) %>%
select(track_name, size_bytes, user_rating, rating_count_tot, rating_count_ver, price, app_desc)
#get highest rated social media app names
Highest_Rated_Social <-
Social_With_Desc %>%
filter(user_rating >= 3.5) %>%
arrange(desc(rating_count_tot)) %>%
select(track_name, size_bytes, user_rating, user_rating_ver, rating_count_tot, rating_count_ver, price, app_desc)
The following graphs show a how the number of user ratings ranges based on the price. From this, I was able to view how the number of reviews can impact the overall rating of paid apps, and how the difference in those prices can have an effect. Each of the graphs below allowed me to view the number of apps that have a significantly higher number of reviews, and how those app ratings are impacted.
#compare ratings and number of ratings for paid apps.
Paid_Music <-
Highest_Rated_Music %>%
filter(price > 0.00)
paid_frame <- ggplot(data=Paid_Music,aes(x=price,y=rating_count_tot))+geom_point()+aes(colour=user_rating)+scale_y_log10()
rating_count_standard <- geom_hline(yintercept = 1000)
paid_frame+rating_count_standard

This shows the same analysis as above for Social Networking applications. There are a significantly smaller number of
Paid_Social <-
Highest_Rated_Social %>%
filter(price > 0.00)
paid_frame <- ggplot(data=Paid_Social,aes(x=price,y=rating_count_tot))+geom_point()+aes(colour=user_rating)+scale_y_log10()
rating_count_standard <- geom_hline(yintercept = 1000)
paid_frame+rating_count_standard

Another point that I thought would be interesting to see how many descriptions for higher rated music applications actually contain the word “music”. Doing this can allow me to improve the description of my application.
#Descs_with_music <-
Highest_Rated_Music %>%
filter(grepl("music", app_desc)) %>%
select(track_name, user_rating, app_desc) %>%
arrange(desc(user_rating))
The name of my application contains the word “Party”. One final thing I thought would be interesting would be to find the number of music or social applications that also have “Party” in their title. As seen below, the conclusion is that not many apps in these specific categories use “Party” in their name.
Find_Names <- function(data) {
num_of_titles <-
filter(grepl("party", track_name)) %>%
summarise(num_of_apps = n())
return(num_of_titles)
}
Find_Names(Social_Network_App_Data)
Find_Names(Music_App_Data)
NA
LS0tDQp0aXRsZTogIkFwcF9TdG9yZV9BbmFseXNpcyINCmF1dGhvcjogQW5nZWxvIEt3YWsNCmRhdGU6IDEyLzE2LzIwMTkNCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNClB1cnBvc2U6DQpUaGUgcHVycG9zZSBvZiB0aGlzIHByb2plY3QgaXMgdG8gYW5hbHl6ZSBhIG51bWJlciBvZiB0cmVuZHMgaW4gdGhlIEFwcGxlIEFwcCBTdG9yZS4gSSBjaG9zZSB0byBkbyB0aGlzIHByb2plY3QgdXNpbmcgdGhpcyBkYXRhIGJlY2F1c2UgSSdtIGludGVyZXN0ZWQgaW4gbW9iaWxlIGFwcCBkZXZlbG9wbWVudCBhbmQgY3VycmVudGx5IGhhdmUgYW4gYXBwbGljYXRpb24gb24gdGhlIEFwcCBTdG9yZS4gU3BlY2lmaWNhbGx5LCBteSBhcHBsaWNhdGlvbiBpcyBmb3IgbXVzaWMgYW5kIHNvY2lhbCBtZWRpYSwgc28gSSB3aWxsIGJlIGhlYXZpbHkgYW5hbHl6aW5nIHRoZXNlIGdlbnJlcyBzcGVjaWZpY2FsbHkuIA0KDQpgYGB7cn0NCiMgY2xlYW4gdXAgd29ya3NwYWNlIGVudmlyb25tZW50DQpybShsaXN0ID0gbHMoKSkNCiNQYWNrYWdlcw0KbGlicmFyeShtb3NhaWMpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoRGF0YUNvbXB1dGluZykNCmxpYnJhcnkocGFydHkpDQpgYGANCg0KVGhlIGNodW5rIGJlbG93IGxvYWRzIGFsbCBkYXRhIGZyb20gdGhlIHR3byBkYXRhc2V0cyByZWdhcmRpbmcgdGhlIEFwcGxlIEFwcCBTdG9yZQ0KYGBge3J9DQojVGhpcyBkYXRhc2V0IGNvbnRhaW5zIGEgbnVtYmVyIG9mIGFuYWx5dGljcyBhYm91dCBvdmVyIDcwMDAgYXBwbGljYXRpb25zIG9uIHRoZSBBcHAgU3RvcmUuDQojSW5mb3JtYXRpb24gaW5jbHVkZXMgcmF0aW5nLCBwcmljZSwgZ2VucmUsIGV0Yy4NCg0KZGF0YXNldF8xIDwtICdDOi9Vc2Vycy9hbmdlbC9Ecm9wYm94L1Blbm4gU3RhdGUvU1RBVCAxODQvUHJvamVjdC9BcHBfU3RvcmVfQW5hbHlzaXMvQXBwbGVTdG9yZS5jc3YnDQoNCkFwcF9TdG9yZV9EYXRhIDwtIHJlYWQuY3N2KGZpbGUgPSBkYXRhc2V0XzEsIGhlYWRlcj1UUlVFLCBzZXA9IiwiKQ0KDQojVGhpcyBkYXRhc2V0IGNvbnRhaW5zIGEgbnVtYmVyIG9mIGFuYWx5dGljcyBhYm91dCBvdmVyIDcwMDAgYXBwbGljYXRpb25zIG9uIHRoZSBBcHAgU3RvcmUuDQojSW5mb3JtYXRpb24gaW5jbHVkZXMgcmF0aW5nLCBwcmljZSwgZ2VucmUsIGV0Yy4NCmRhdGFzZXRfMiA8LSAnQzovVXNlcnMvYW5nZWwvRHJvcGJveC9QZW5uIFN0YXRlL1NUQVQgMTg0L1Byb2plY3QvQXBwX1N0b3JlX0FuYWx5c2lzL2FwcGxlU3RvcmVfZGVzY3JpcHRpb24uY3N2Jw0KDQpBcHBfU3RvcmVfRGVzY3JpcHRpb25fRGF0YSA8LSByZWFkLmNzdihmaWxlID0gZGF0YXNldF8yLCBoZWFkZXI9VFJVRSwgc2VwPSIsIikNCmBgYA0KDQojIyBTYW1wbGUgb2YgdGhlIEFwcCBTdG9yZSBEYXRhc2V0DQpgYGB7cn0NCkFwcF9TdG9yZV9EYXRhICU+JQ0KICBzYW1wbGVfbihzaXplID0gMTApDQpgYGANCiMjIFNhbXBsZSBvZiB0aGUgRGVzY3JpcHRpb24gRGF0YXNldA0KYGBge3J9DQpBcHBfU3RvcmVfRGVzY3JpcHRpb25fRGF0YSAlPiUNCiAgc2FtcGxlX24oc2l6ZSA9IDEwKQ0KYGBgDQojIEdlbmVyYWwgQW5hbHlzaXMNClRoZSBmaXJzdCB0aGluZyB0aGF0IEkgd2FudGVkIHRvIGRvIHdpdGggdGhpcyBkYXRhc2V0IGlzIGdhdGhlciBzb21lIGdlbmVyYWwgc3RhdGlzdGljcyBhYm91dCB0aGUgYXBwcyB3aXRoaW4gdGhlIEFwcCBTdG9yZS4gQmVsb3cgc2hvd3Mgc2V2ZXJhbCBtZWFuIHZhbHVlcyBjYWxjdWxhdGVkIGJhc2VkIG9uIHRoaXMgZGF0YS4NCmBgYHtyfQ0KI1RoaXMgY29kZSBkaXNwbGF5cyB0aGUgbWVhbiBzaXplIG9mIGVhY2ggYXBwLCBhcHAgcmF0aW5nLCBhbmQgbnVtYmVyIG9mIGxhbmd1YWdlcyBzdXBwb3J0ZWQgd2l0aGluIGFuIGFwcC4NCkFwcF9TdG9yZV9EYXRhICU+JQ0KICBzdW1tYXJpc2UobnVtX2FwcHMgPSBuKCksDQogICAgICAgICAgICBtZWFuX2FwcF9zaXplID0gbWVhbihzaXplX2J5dGVzKSwNCiAgICAgICAgICAgIG1lYW5fYXBwX3JhdGluZyA9IG1lYW4odXNlcl9yYXRpbmcpLA0KICAgICAgICAgICAgbWVhbl9zdXBwb3J0ZWRfbGFuZ3VhZ2VzID0gbWVhbihsYW5nLm51bSkpDQpgYGANCg0KIyMgQXBwIFN0b3JlIEJyZWFrZG93bg0KVGhlIGZvbGxvd2luZyBpcyBhIGdlbmVyYWwgYnJlYWtkb3duIG9mIHRoZSBjYXRlZ29yaWVzIG9mIGFwcHMgaW4gdGhlIEFwcCBTdG9yZS4gQmVsb3cgaXMgYSBjaGFydCBjb250YWluaW5nIHRoZSBzcGVjaWZpYyBudW1iZXIgb2YgYXBwcyBpbiBlYWNoIGNhdGVnb3J5LCBpbiBhZGRpdGlvbiB0byBhIHBsb3Qgc2hvd2luZyB0aGVzZSBudW1iZXJzLiBUaGlzIHBsb3Qgc2hvd3MgYSBtb3JlIHZpc3VhbGx5IGFwcGVhbGluZyB3YXkgb2YgbG9va2luZyBhdCBqdXN0IGhvdyBkaXZlcnNlIHRoZSBBcHAgU3RvcmUgcmVhbGx5IGlzLiBCYXNlZCBvbiB0aGlzIGRhdGEsIGl0J3MgdmVyeSBjbGVhciB0aGF0IGdhbWVzIHRha2UgdXAgYSB2ZXJ5IGxhcmdlIHBvcHVsYXRpb24gaW4gdGhlIEFwcCBTdG9yZS4gDQpgYGB7cn0NCkFwcF9DYXRlZ29yaWVzIDwtIEFwcF9TdG9yZV9EYXRhICU+JQ0KICBncm91cF9ieShwcmltZV9nZW5yZSkgJT4lDQogIHN1bW1hcmlzZShudW1fb25fc3RvcmUgPSBuKCkpDQoNCkFwcF9DYXRlZ29yaWVzDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YT1BcHBfQ2F0ZWdvcmllcyxhZXMoeD1wcmltZV9nZW5yZSx5PW51bV9vbl9zdG9yZSAsZmlsbD1wcmltZV9nZW5yZSkpK2dlb21fYmFyKHN0YXQ9J2lkZW50aXR5Jyxwb3NpdGlvbj0nc3RhY2snLCB3aWR0aD0uOSkrdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41KSkrIHhsYWIoJ0FwcCBDYXRlZ29yeScpICsgeWxhYignTnVtYmVyIG9uIFN0b3JlJykNCmBgYA0KDQojIFNwZWNpZmljIGNsYXNzaWZpY2F0aW9uIGZvciBNdXNpYyBhbmQgU29jaWFsIE1lZGlhDQpCZWNhdXNlIG15IGFwcGxpY2F0aW9uIGlzIHNwZWNpZmljYWxseSByZWxhdGVkIHRvIG11c2ljIGFuZCBzb2NpYWwgbmV0d29ya2luZywgSSBkZWNpZGVkIHRvIGZvY3VzIG9uIHRoZXNlIGNhdGVnb3JpZXMuIA0KYGBge3J9DQojbXVzaWMgZGF0YQ0KTXVzaWNfQXBwX0RhdGEgPC0NCiAgQXBwX1N0b3JlX0RhdGEgJT4lDQogIGZpbHRlcihwcmltZV9nZW5yZSA9PSAnTXVzaWMnKQ0KDQojc29jaWFsIG5ldHdvcmsgZGF0YQ0KU29jaWFsX05ldHdvcmtfQXBwX0RhdGEgPC0NCiAgQXBwX1N0b3JlX0RhdGEgJT4lDQogIGZpbHRlcihwcmltZV9nZW5yZSA9PSAnU29jaWFsIE5ldHdvcmtpbmcnKQ0KDQojam9pbiB0aGUgbXVzaWMgZGF0YSB3aXRoIGl0J3MgZGVzY3JpcHRpb24gDQpNdXNpY19XaXRoX0Rlc2MgPC0gTXVzaWNfQXBwX0RhdGEgJT4lDQpsZWZ0X2pvaW4oQXBwX1N0b3JlX0Rlc2NyaXB0aW9uX0RhdGEsICdpZCcgPSAnaWQnKQ0KDQojam9pbiBzb2NpYWwgbmV0d29yayBkYXRhIHdpdGhuIGl0cyBkZXNjcmlwdGlvbg0KU29jaWFsX1dpdGhfRGVzYyA8LSBTb2NpYWxfTmV0d29ya19BcHBfRGF0YSAlPiUNCmxlZnRfam9pbihBcHBfU3RvcmVfRGVzY3JpcHRpb25fRGF0YSwgJ2lkJyA9ICdpZCcpDQpgYGANCg0KYGBge3J9DQojZ2V0IG1vc3QgcmF0ZWQgYW5kIGhpZ2hlc3QgcmF0ZWQgbXVzaWMgYXBwIG5hbWVzDQpIaWdoZXN0X1JhdGVkX011c2ljIDwtDQogIE11c2ljX1dpdGhfRGVzYyAlPiUNCiAgZmlsdGVyKHVzZXJfcmF0aW5nID49IDMuNSkgJT4lDQogIGFycmFuZ2UoZGVzYyhyYXRpbmdfY291bnRfdG90KSkgJT4lDQogIHNlbGVjdCh0cmFja19uYW1lLCBzaXplX2J5dGVzLCB1c2VyX3JhdGluZywgcmF0aW5nX2NvdW50X3RvdCwgcmF0aW5nX2NvdW50X3ZlciwgcHJpY2UsIGFwcF9kZXNjKQ0KDQojZ2V0IGhpZ2hlc3QgcmF0ZWQgc29jaWFsIG1lZGlhIGFwcCBuYW1lcw0KSGlnaGVzdF9SYXRlZF9Tb2NpYWwgPC0NCiAgU29jaWFsX1dpdGhfRGVzYyAlPiUNCiAgZmlsdGVyKHVzZXJfcmF0aW5nID49IDMuNSkgJT4lDQogIGFycmFuZ2UoZGVzYyhyYXRpbmdfY291bnRfdG90KSkgJT4lDQogIHNlbGVjdCh0cmFja19uYW1lLCBzaXplX2J5dGVzLCB1c2VyX3JhdGluZywgdXNlcl9yYXRpbmdfdmVyLCByYXRpbmdfY291bnRfdG90LCByYXRpbmdfY291bnRfdmVyLCBwcmljZSwgYXBwX2Rlc2MpDQpgYGANCg0KVGhlIGZvbGxvd2luZyBncmFwaHMgc2hvdyBhIGhvdyB0aGUgbnVtYmVyIG9mIHVzZXIgcmF0aW5ncyByYW5nZXMgYmFzZWQgb24gdGhlIHByaWNlLiBGcm9tIHRoaXMsIEkgd2FzIGFibGUgdG8gdmlldyBob3cgdGhlIG51bWJlciBvZiByZXZpZXdzIGNhbiBpbXBhY3QgdGhlIG92ZXJhbGwgcmF0aW5nIG9mIHBhaWQgYXBwcywgYW5kIGhvdyB0aGUgZGlmZmVyZW5jZSBpbiB0aG9zZSBwcmljZXMgY2FuIGhhdmUgYW4gZWZmZWN0LiBFYWNoIG9mIHRoZSBncmFwaHMgYmVsb3cgYWxsb3dlZCBtZSB0byB2aWV3IHRoZSBudW1iZXIgb2YgYXBwcyB0aGF0IGhhdmUgYSBzaWduaWZpY2FudGx5IGhpZ2hlciBudW1iZXIgb2YgcmV2aWV3cywgYW5kIGhvdyB0aG9zZSBhcHAgcmF0aW5ncyBhcmUgaW1wYWN0ZWQuDQpgYGB7cn0NCiNjb21wYXJlIHJhdGluZ3MgYW5kIG51bWJlciBvZiByYXRpbmdzIGZvciBwYWlkIGFwcHMuIA0KUGFpZF9NdXNpYyA8LQ0KICBIaWdoZXN0X1JhdGVkX011c2ljICU+JQ0KICBmaWx0ZXIocHJpY2UgPiAwLjAwKQ0KDQpwYWlkX2ZyYW1lIDwtIGdncGxvdChkYXRhPVBhaWRfTXVzaWMsYWVzKHg9cHJpY2UseT1yYXRpbmdfY291bnRfdG90KSkrZ2VvbV9wb2ludCgpK2Flcyhjb2xvdXI9dXNlcl9yYXRpbmcpK3NjYWxlX3lfbG9nMTAoKSANCiNUaGlzIHNwZWNpZmljYWxseSBzZXRzIGEgbGF5ZXIgYWJvdmUgdGhlIGdyYXBoIGF0IDEwMDAgcmV2aWV3cy4NCnJhdGluZ19jb3VudF9zdGFuZGFyZCA8LSBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxMDAwKQ0KI1RoaXMgY29tYmluZXMgdGhlIGZyYW1lIGFuZCBsaW5lIGxheWVycy4gDQpwYWlkX2ZyYW1lK3JhdGluZ19jb3VudF9zdGFuZGFyZA0KYGBgDQoNClRoaXMgc2hvd3MgdGhlIHNhbWUgYW5hbHlzaXMgYXMgYWJvdmUgZm9yIFNvY2lhbCBOZXR3b3JraW5nIGFwcGxpY2F0aW9ucy4gVGhlcmUgYXJlIGEgc2lnbmlmaWNhbnRseSBzbWFsbGVyIG51bWJlciBvZiANCmBgYHtyfQ0KUGFpZF9Tb2NpYWwgPC0NCiAgSGlnaGVzdF9SYXRlZF9Tb2NpYWwgJT4lDQogIGZpbHRlcihwcmljZSA+IDAuMDApDQojY29tcGFyZSByYXRpbmdzIGFuZCBudW1iZXIgb2YgcmF0aW5ncyBmb3IgcGFpZCBhcHBzLg0KcGFpZF9mcmFtZSA8LSBnZ3Bsb3QoZGF0YT1QYWlkX1NvY2lhbCxhZXMoeD1wcmljZSx5PXJhdGluZ19jb3VudF90b3QpKStnZW9tX3BvaW50KCkrYWVzKGNvbG91cj11c2VyX3JhdGluZykrc2NhbGVfeV9sb2cxMCgpIA0KI1RoaXMgc3BlY2lmaWNhbGx5IHNldHMgYSBsYXllciBhYm92ZSB0aGUgZ3JhcGggYXQgMTAwMCByZXZpZXdzLg0KcmF0aW5nX2NvdW50X3N0YW5kYXJkIDwtIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEwMDApDQojVGhpcyBjb21iaW5lcyB0aGUgZnJhbWUgYW5kIGxpbmUgbGF5ZXJzLiANCnBhaWRfZnJhbWUrcmF0aW5nX2NvdW50X3N0YW5kYXJkDQpgYGANCg0KDQpBbm90aGVyIHBvaW50IHRoYXQgSSB0aG91Z2h0IHdvdWxkIGJlIGludGVyZXN0aW5nIHRvIHNlZSBob3cgbWFueSBkZXNjcmlwdGlvbnMgZm9yIGhpZ2hlciByYXRlZCBtdXNpYyBhcHBsaWNhdGlvbnMgYWN0dWFsbHkgY29udGFpbiB0aGUgd29yZCAibXVzaWMiLiBEb2luZyB0aGlzIGNhbiBhbGxvdyBtZSB0byBpbXByb3ZlIHRoZSBkZXNjcmlwdGlvbiBvZiBteSBhcHBsaWNhdGlvbi4gDQpgYGB7cn0NCiNEZXNjc193aXRoX211c2ljIDwtDQogIEhpZ2hlc3RfUmF0ZWRfTXVzaWMgJT4lDQogIGZpbHRlcihncmVwbCgibXVzaWMiLCBhcHBfZGVzYykpICU+JQ0KICBzZWxlY3QodHJhY2tfbmFtZSwgdXNlcl9yYXRpbmcsIGFwcF9kZXNjKSAlPiUNCiAgYXJyYW5nZShkZXNjKHVzZXJfcmF0aW5nKSkNCmBgYA0KDQpUaGUgbmFtZSBvZiBteSBhcHBsaWNhdGlvbiBjb250YWlucyB0aGUgd29yZCAiUGFydHkiLiBPbmUgZmluYWwgdGhpbmcgSSB0aG91Z2h0IHdvdWxkIGJlIGludGVyZXN0aW5nIHdvdWxkIGJlIHRvIGZpbmQgdGhlIG51bWJlciBvZiBtdXNpYyBvciBzb2NpYWwgYXBwbGljYXRpb25zIHRoYXQgYWxzbyBoYXZlICJQYXJ0eSIgaW4gdGhlaXIgdGl0bGUuIEFzIHNlZW4gYmVsb3csIHRoZSBjb25jbHVzaW9uIGlzIHRoYXQgbm90IG1hbnkgYXBwcyBpbiB0aGVzZSBzcGVjaWZpYyBjYXRlZ29yaWVzIHVzZSAiUGFydHkiIGluIHRoZWlyIG5hbWUuIA0KYGBge3J9DQpGaW5kX05hbWVzIDwtIGZ1bmN0aW9uKGRhdGEpIHsNCiAgbnVtX29mX3RpdGxlcyA8LQ0KICAgIGRhdGEgJT4lDQogICAgZmlsdGVyKGdyZXBsKCJwYXJ0eSIsIHRyYWNrX25hbWUpKSAlPiUNCiAgICBzdW1tYXJpc2UobnVtX29mX2FwcHMgPSBuKCkpDQogIA0KICByZXR1cm4obnVtX29mX3RpdGxlcykNCn0NCg0KRmluZF9OYW1lcyhTb2NpYWxfTmV0d29ya19BcHBfRGF0YSkNCkZpbmRfTmFtZXMoTXVzaWNfQXBwX0RhdGEpDQpgYGA=